/*
 * mtf.cpp
 */

#include "./mtf.h"
#include <iostream>

void mtf_inicializar(Tipo_MTFTabla * const mTFTabla) {
	// Cargo la tabla con los caracteres ASCII de menor a mayor.
	for (unsigned int contador = 0; contador < RANGO; ++contador) {
		mTFTabla->tabla[contador] = contador;
	}
}

void mtf_codificar(Tipo_MTFTabla * const mTFTabla, unsigned char * const bloque, unsigned int const bloqueLongitud) {
	unsigned char caracterAProcesar;
	unsigned char tablaPosicion;
	unsigned char caracterAnterior;
	unsigned char caracterAnteriorAux;
	// Recorro el bloque de principio a fin.
	for (unsigned int bloquePosicion = 0; bloquePosicion < bloqueLongitud; ++bloquePosicion) {
		caracterAProcesar = bloque[bloquePosicion];  // Cargo (desde el bloque) el caracter a procesar.
		if (mTFTabla->tabla[0] == caracterAProcesar) {  // Si el caracter a emitir es el primero de la tabla.
			bloque[bloquePosicion] = 0;  // Emito un cero.
		} else {  // Si el caracter a emitir no es el primero de la tabla.
			caracterAnterior = mTFTabla->tabla[1];  // Cargo el último caracter reemplazado en la tabla.
			mTFTabla->tabla[1] = mTFTabla->tabla[0];  // "Bajo" el primer caracter de la tabla una fila.
			// "Bajo" todos los caracteres de la tabla, una fila, hasta llegar al caracter a emitir.
			for (tablaPosicion = 1; caracterAnterior != caracterAProcesar;) {
				++tablaPosicion;
				caracterAnteriorAux = mTFTabla->tabla[tablaPosicion];
				mTFTabla->tabla[tablaPosicion] = caracterAnterior;
				if (caracterAnteriorAux != caracterAProcesar) {  // Si el caracter actual de la tabla no es el caracter a procesar.
					++tablaPosicion;  // Me preparo para procesar la siguiente fila de la tabla.
					caracterAnterior = mTFTabla->tabla[tablaPosicion];  // Cargo el último caracter reemplazado en la tabla.
					mTFTabla->tabla[tablaPosicion] = caracterAnteriorAux;  // Cargo en la tabla el caracter de la fila anterior.
				} else {  // Si el caracter actual de la tabla es el caracter a procesar.
					break;  // Dejo de "bajar" los caracteres una fila en la tabla.
				}
			}
			mTFTabla->tabla[0] = caracterAProcesar;  // Cargo el caracter a procesar al tope de la tabla.
			bloque[bloquePosicion] = tablaPosicion;  // Emito la posición en la tabla donde estaba el caracter a procesar.
		}
	}
}

void mtf_decodificar(Tipo_MTFTabla * const mTFTabla, unsigned char * const bloque, unsigned int const bloqueLongitud) {
	unsigned char tablaPosicionAProcesar;  // Indica la posición de la tabla donde está el caracter a emitir.
	// Recorro el bloque de principio a fin.
	for (unsigned int bloquePosicion = 0; bloquePosicion < bloqueLongitud; ++bloquePosicion) {
		tablaPosicionAProcesar = bloque[bloquePosicion];  // Cargo (desde el bloque) la posición de la tabla donde está el caracter a emitir.
		unsigned char caracter = mTFTabla->tabla[tablaPosicionAProcesar];  // Cargo el caracter a emitir.
		bloque[bloquePosicion] = caracter;  // Emito el caracter (directamente al bloque).
		// Recorro la tabla desde la posición del caracter emitido hasta el comienzo, actualizándola.
		for (; tablaPosicionAProcesar > 0; --tablaPosicionAProcesar) {
			mTFTabla->tabla[tablaPosicionAProcesar] = mTFTabla->tabla[tablaPosicionAProcesar - 1];  // "Bajo" todos los caracteres, una fila en la tabla.
		}
		mTFTabla->tabla[0] = caracter;  // Cargo el caracter emitido al tope de la tabla.
	}
}

